/**
 * Database 数据库操作基类
 * @module database
 */
export class Database {
  static engine;
  db; // 数据库连接实例

  async #query(sql, ...params) {
    // 兼容 sql 模板字符串
    if (Array.isArray(sql))
      sql = String.raw({ raw: sql }, ...Array(params.length).fill("?"));
    else {
      if (params.length == 1 && Array.isArray(params[0])) [params] = params;
    }
    return await this.run(sql, params);
  }

  /**
   * 查询多条数据
   * @param {string | string[]} sql 查询语句
   * @param  {...any} params
   * @returns { Promise<any[]> }
   */
  async findMany(sql, ...params) {
    return this.#query(sql, ...params);
  }

  /**
   * 查询单条数据
   * @param {string | string[]} sql 查询语句
   * @param  {...any} params
   * @returns { Promise<any> }
   */
  async findOne(sql, ...params) {
    const [rs] = await this.#query(sql, ...params);
    return rs;
  }

  /**
   * 插入数据
   * @param {string | string[]} sql 插入语句
   * @param  {...any} params
   * @returns {Promise<object>}
   */
  async insert(sql, ...params) {
    const { insertId } = await this.#query(sql, ...params);
    if (Array.isArray(sql))
      sql = String.raw({ raw: sql }, ...Array(params.length).fill("?"));
    return this.findOne(
      `select * from ${getTableName(sql)} where id = ${insertId}`
    );
  }

  /**
   * 更新数据
   * @param {string | string[]} sql 更新语句
   * @param  {...any} params
   * @returns {Promise<number>}
   */
  async update(sql, ...params) {
    const { affectedRows } = await this.#query(sql, ...params);
    return affectedRows;
  }

  /**
   * 删除数据
   * @param {string | string[]} sql 删除语句
   * @param  {...any} params
   * @returns {Promise<object>}
   */
  async delete(sql, ...params) {
    const { affectedRows } = await this.#query(sql, ...params);
    return affectedRows;
  }

  /**
   * 关闭数据库连接
   * @returns {Promise<void>}
   */
  async end() {}
}

/**
 * 获取插入语句中的表名
 * @param {string} sql 插入语句
 * @returns {string}
 */
const regex = /INSERT\s+INTO\s+([^\s\(]+)/i;
export function getTableName(sql) {
  const match = sql.match(regex);
  return match ? match[1] : null;
}
